/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is
 *
 * java-concurrency-presentation:
 * concurrency presentation tutorial.
 *
 * The Initial Developer of the Original Code is
 * Marco Antonio Villalobos, Jr.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): None.
 *
 * ***** END LICENSE BLOCK *****
 */

package presentation.concurrency.slides;

import java.util.ArrayList;
import java.util.List;

/**
 * Stack example used to show how to use wait, notify, and notifyAll.
 *
 * Given threads A, B, and Stack S, then
 *
 * When A does S.pop() when S is empty, A will wait until B does S.add(item).
 * When A does S.add(item) when S is at capacity, A will wait until B does S.pop().
 */
public class BoundedStackWithImplicitLock<T> {

    /** The capacity of this stack. */
    private final int capacity;

    /** The data-structure containing the items add into this stack. */
    private final List<T> items;

    /** The current size of this stack. */
    private int current = 0;

    /**
     * Initializes this stack with its maximum capacity.
     *
     * @param capacity The maximum capacity of this stack.
     */
    public BoundedStackWithImplicitLock(int capacity) {
        this.capacity = capacity;
        this.items = new ArrayList<T>(capacity);
    }

    /**
     * Pops an item from the stack.  Will wait until there is something to pop.
     *
     * @return The value on the top of stack.
     */
    public synchronized T pop() throws InterruptedException {
        while (current <= 0) { // check if empty
            wait();
        }
        T v = items.get(current);
        current--;
        notify();
        return v;
    }

    /**
     * Pushes an item on top of the stack.  Will wait if the stack is full.
     *
     * @param item The item to add onto the stack.
     */
    public synchronized void push(T item) throws InterruptedException {
        while(current >= capacity) { // check if at capacity
            wait();
        }
        items.add(item);
        current++;
        notify();
    }

    /**
     * Retrieves the current size of this stack.
     *
     * @return The current size of the stack.
     */
    public synchronized int getSize() {
        return current;
    }
}